﻿using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using IWMAG.Scripting.Interpreter;

namespace IWMAG.Scripting.DevelopmentEnvironment
{
    /// <summary>
    /// Interaction logic for RunWindow.xaml
    /// </summary>
    public partial class RunWindow : Window
    {
        public RunWindow()
        {
            InitializeComponent();
        }

        Task runTask;
        CancellationTokenSource runCancellor = new CancellationTokenSource();
        TextWriter defaultWriter;
        public ScriptEngine Engine { get; set; }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            defaultWriter = Console.Out;
            this.Closing += (s, args)=>
                {
                    Console.SetOut(defaultWriter);
                };

            Console.SetOut(new TextWriterImpl(this, defaultWriter));
        }

        void RunInBackground()
        {

            playPauseSemaphore.Wait(runCancellor.Token);
            bool errorOccured = false;
            try
            {
                Engine.Start("boot");
                while (Engine.HasOpenContexts && !runCancellor.IsCancellationRequested)
                {
                    Engine.Update(1000f);
                    //Thread.Sleep(50);
                    playPauseSemaphore.Wait(runCancellor.Token);
                }
            }
            catch (Exception e)
            {
                if (e as OperationCanceledException == null)
                {
                    Console.WriteLine();
                    Console.WriteLine("----- ----- ----- PROGRAM CRASHED ----- ----- -----");
                    Console.WriteLine("Exception Message: " + e.Message);
                    Console.WriteLine("File a bug, if crash was an error");
                    errorOccured = true;
                }
            }
            finally
            {
                Dispatcher.Invoke(new Action(() =>
                {
                    btnPlayPause.IsEnabled = false;
                    btnStop.IsEnabled = false;
                    if (!errorOccured)
                    {
                        Console.WriteLine();
                        Console.WriteLine();
                        Console.WriteLine("----- ----- ----- PROGRAM COMPLETED ----- ----- -----");
                    }               
                }));
            }
        }

        private void btnBug_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Not Yet Implemented :(", "iwmag");
        }

        ManualResetEventSlim playPauseSemaphore = new ManualResetEventSlim(false);

        private void btnPlayPause_Click(object sender, RoutedEventArgs e)
        {
            if (playPauseSemaphore.IsSet)
            {
                playPauseSemaphore.Reset();
                btnPlayPause.Content = "Play";
            }
            else
            {
                btnPlayPause.Content = "Pause";
                playPauseSemaphore.Set();            
            }
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            runCancellor.Cancel();
        }



        internal void FocusGranted()
        {
            if (Engine == null || !Engine.Compiled)
            {
                this.Close();
            }
            

            runTask = new Task(RunInBackground, runCancellor.Token);
            runTask.Start();
        }

        public class TextWriterImpl : TextWriter
        {
            RunWindow backingWindow;
            private TextWriter defaultWriter;

            public TextWriterImpl(RunWindow runWindow, TextWriter defaultWriter)
            {
                this.backingWindow = runWindow;
                this.defaultWriter = defaultWriter;
            }
            public override void Write(string value)
            {
                if (!backingWindow.CheckAccess())
                {
                    backingWindow.Dispatcher.Invoke(new Action(() =>
                    {
                        this.Write(value);
                    }));
                    return;
                }
                WriteImpl(value);
            }

            private void WriteImpl(string value)
            {
                backingWindow.tbOutput.Text += value;
                defaultWriter.Write(value);
            }

            public override void Write(char value)
            {
                if (!backingWindow.CheckAccess())
                {
                    backingWindow.Dispatcher.Invoke(new Action(() =>
                        {
                            this.Write(value);
                        }));
                    return;
                }
                WriteImpl(value.ToString());
            }

            public override void WriteLine(string value)
            {
                if (!backingWindow.CheckAccess())
                {
                    backingWindow.Dispatcher.Invoke(new Action(() =>
                    {
                        this.WriteLine(value);
                    }));
                    return;
                }
                WriteImpl(value + Environment.NewLine);
            }

            public override Encoding Encoding
            {
                get { return defaultWriter.Encoding; }
            }
        }
    }
}
